/*
 * Copyright 2011 Philippe Blanc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package me.l1k3.fx.client;

import me.l1k3.core.client.Core;
import me.l1k3.core.client.queue.Queue;
import me.l1k3.fx.client.event.FXEvent;
import me.l1k3.fx.client.event.FXEventHandler;
import me.l1k3.fx.client.impl.FXBase;
import me.l1k3.fx.client.inter.FX;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;

public class FXLoops extends FXBase implements FXEventHandler {
	public final static int INFINITY = -1000;
	
	private FX fx;
	private int loops;
	private int count;
	private int duration;
	private int delayBetweenLoop;
	private boolean toggle;	
	private JavaScriptObject handleFire;

	public FXLoops(FX fx) {
		this(fx, 500, 100, true);
	}
	
	public FXLoops(FX fx, int loops, int delayBetweenLoop, boolean toggle) {
		this.fx = fx;
		this.loops = loops;
		this.delayBetweenLoop = delayBetweenLoop;
		this.toggle = toggle;
		
		fx.addFXEventHandler(this);
	}
	
	@Override
    public FX init(Element element) {
        fx.init(element);
        
        return this;
    }
	
	@Override
	public String getType() {
	    return fx.getType();
	}
	
	@Override
	public Queue animate() {
	    return animate(1000);
    }
	
	@Override
	public Queue animate(int duration) {
	    onStart();
	    this.duration = duration;
		count = 0;
		fx.animate(duration);
		return this;
	}
	
	@Override
	public Queue animate(int duration, int firstTimeDelay, boolean toggle) {
	    onStart();
	    count = 0;
	    this.duration = duration;
        fx.animate(duration, firstTimeDelay, toggle);
        return this;
    }

	public int getLoops() {
		return loops;
	}

	public void setLoops(int loops) {
		this.loops = loops;
	}

	public int getDuration() {
		return duration;
	}

	public void setDuration(int duration) {
		this.duration = duration;
	}

	public int getDelay() {
		return delayBetweenLoop;
	}

	public void setDelay(int delay) {
		this.delayBetweenLoop = delay;
	}
	
	/**
	 * @exclude
	 */
    @Override
    public FX toggle() {
        if(!toggle) {
            fx.toggle();
        }
        //else N/A
        
        return this;
    }

    /**
     * @exclude
     */
    @Override
    public FX cancel() {
        fx.cancel();
        
        return this;
    }
	
    /**
     * @exclude
     */
	@Override
	public void onStart(FXEvent event) { }	
	
	/**
	 * @exclude
	 */
	@Override
	public void onComplete(FXEvent event) {
		count++;
		
		if(count<loops || loops==INFINITY) {
		    if(handleFire==null) {
	            handleFire = getFireHandle(this);
	        }
		    
		    if(delayBetweenLoop>0) {
		        Core.createTimeout(handleFire, delayBetweenLoop);
		    }
		    else {
		        fire();
		    }
		}
		else {
			count = 0;
	        onComplete();
		}
	}
	
	protected final void fire() {
	    fx.animate(duration, 0, !toggle);
	}
	
	private final static native JavaScriptObject getFireHandle(FXLoops loops) /*-{  
        return function() {$entry(loops.@me.l1k3.fx.client.FXLoops::fire()());};
    }-*/;
	
    @Override
    public String toString() {
        return fx.toString();
    }
}
